package com.youlu.campus.service.order.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.common.utils.ExcelUtil;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.req.DeliveryOrderSubMsgMQVO;
import com.youlu.campus.entity.VO.req.OrderPostControllerAddressReq;
import com.youlu.campus.entity.VO.req.OrderShippingTaskQueryVO;
import com.youlu.campus.entity.domain.OrderImport;
import com.youlu.campus.entity.ems.EmsPostControllerResult;
import com.youlu.campus.entity.kuaidi100.KuaiDi100PollMapBodyDTO;
import com.youlu.campus.entity.order.SingleOrderBatch;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.cache.CacheOrderService;
import com.youlu.campus.service.cache.CachePayConfigService;
import com.youlu.campus.service.notify.KuaiDi100Service;
import com.youlu.campus.service.order.DeliveryOrderSubMsgService;
import com.youlu.campus.service.order.EMSService;
import com.youlu.campus.service.order.OrderShippingTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class OrderShippingTaskServiceImpl implements OrderShippingTaskService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Lazy
    @Autowired
    private ActivityService activityService;

    @Autowired
    private CacheOrderService cacheOrderService;

    @Autowired
    private DeliveryOrderSubMsgService deliveryOrderSubMsgService;

    @Autowired
    private CachePayConfigService cachePayConfigService;

    @Autowired
    private EMSService emsService;

    @Lazy
    @Autowired
    private KuaiDi100Service kuaiDi100Service;

    @Override
    public Page<OrderShippingTask> list(OrderShippingTaskQueryVO req) {
        log.info(":>>> 开始获取发货批次:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getActivityId())) {
            log.error(":>>> 参数错误");
            throw new BusinessException("参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()));
        if (StringUtils.isNotBlank(req.getStatus())) {
            query.addCriteria(Criteria.where("status").is(req.getStatus()));
        }
        if (StringUtils.isNotBlank(req.getType())) {
            query.addCriteria(Criteria.where("type").is(req.getType()));
        }
        if (StringUtils.isNotBlank(req.getOptLoginName())) {
            query.addCriteria(Criteria.where("optLoginName").is(req.getOptLoginName()));
        }
        query.addCriteria(Criteria.where("deleted").ne(true));
        long count = mongoTemplate.count(query, OrderShippingTask.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
        Sort sort=Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<OrderShippingTask> infos = mongoTemplate.find(query.with(pageRequest), OrderShippingTask.class);
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    @Override
    public boolean update(OrderShippingTask req) {
        log.info(":>>> 开始修改发货批次:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getId())) {
            log.error(":>>> 参数错误");
            throw new BusinessException("参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(req.getName())) {
            update.set("name", req.getName());
        }
        if (StringUtils.isNotBlank(req.getDesc())) {
            update.set("desc", req.getDesc());
        }
        if (StringUtils.isNotBlank(req.getStatus())) {
            update.set("status", req.getStatus());
        }
        update.set("updatedTime", new Date());
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, OrderShippingTask.class);
        return updateResult.getModifiedCount() > 0 ? true : false;
    }

    @Override
    public boolean create(OrderShippingTask req, byte[] inputStream, String fileName, String optLoginName) {
        log.info(":>>> 开始创建发货批次:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || Objects.isNull(inputStream) || StringUtils.isBlank(fileName) || StringUtils.isBlank(optLoginName)) {
            log.error(":>>> 创建发货批次参数错误");
            throw new BusinessException("创建发货批次参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("fileName").is(fileName).and("status").is("0"));
        boolean e = mongoTemplate.exists(query, OrderShippingTask.class);
        if (e) {
            log.error(":>>> 发货批次已经存在:{},{}", req.getActivityId(), fileName);
            throw new BusinessException("发货批次已经存在");
        }
        ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
        req.setCreatedTime(new Date());
        req.setOptLoginName(optLoginName);
        req.setFileName(fileName);
        req.setId(null);
        req.setActivityName(activityInfo.getId());
        req.setStatus("0");
        req = mongoTemplate.insert(req);
        this.importShippingBatch(inputStream, req.getId());
        req.setStatus("2");
        this.update(req);
        return true;
    }

    @Override
    public OrderShippingTask findOne(String id) {
        log.info(":>>> 开始查找发货批次批次:{}", JSON.toJSONString(id));
        if (StringUtils.isBlank(id)) {
            log.error(":>>> 参数错误");
            throw new BusinessException("参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        OrderShippingTask batch = mongoTemplate.findOne(query, OrderShippingTask.class);
        return batch;
    }

    @Override
    public boolean cancel(String id) {
        OrderShippingTask task = this.findOne(id);
        if (Objects.isNull(task)) {
            log.error(":>>> 任务不存在:{}", id);
            throw new BusinessException("任务不存在");
        }
        if (!"3".equals(task.getStatus())) {
            log.error(":>>> 任务状态错误:{},状态不是:已确认", id);
            throw new BusinessException("任务状态不是:已确认");
        }
        //    * 任务类型,0:发货,1:补发,2:撤销发货,3:撤销补发
        switch (task.getType()) {
            case "0":
                this.cancelShipping(task);
                break;
            case "1":
                this.cancelReeShipping(task);
                break;
            case "2":
                // 回滚撤销发货
                this.cancelRedoShipping(task);
                break;
            case "3":
                // 撤销补发
                this.cancelRedoReeShipping(task);
                break;
            default:
                break;

        }
        return true;
    }

    @Override
    public boolean preDo(String id) {
        return false;
    }

    @Override
    public boolean done(String id, String ip, String optUserName) {
        OrderShippingTask task = this.findOne(id);
        if (Objects.isNull(task)) {
            log.error(":>>> 任务不存在:{}", id);
            throw new BusinessException("任务不存在");
        }
        if (!"2".equals(task.getStatus())) {
            log.error(":>>> 任务状态错误:{},状态不是:待确认", id);
            throw new BusinessException("任务状态不是:待确认");
        }
        // 任务类型,0:发货,1:补发,2:撤销发货记录,3:撤销补发记录
        switch (task.getType()) {
            case "0":
                this.shipping(task);
                break;
            case "1":
                this.reeShipping(task);
                break;
            case "2":
                this.redoShipping(task);
                break;
            case "3":
                this.redoReeShipping(task);
                break;
            default:
                break;

        }
        return true;
    }

    @Override
    public boolean delete(String id) {
        Query query = checkIdAndQuery(id);
        Update update = new Update();
        //状态,0:待处理,1:取消,2:预合单,3:合单中,4:待确认,5:已确认
        update.set("deleted", true);
        update.set("updatedTime", new Date());
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, OrderShippingTask.class);
        return updateResult.getModifiedCount() > 0 ? true : false;
    }

    @Override
    public boolean reverse(byte[] inputStream, String fileName, String optLoginName, String activityId) {
        return false;
    }

    @Override
    public EmsPostControllerResult findPostControllerByOrderNo(String orderNo) {
        log.info("订单地址查询管控 OrderShippingTaskService.findPostControllerByOrderNo orderNo ->{}",orderNo);
        Query query = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        OrderInfo order = this.mongoTemplate.findOne(query, OrderInfo.class);
        if(Objects.isNull(order)){
            throw new BusinessException("订单不存在");
        }
        EmsPostControllerResult postControllerResult = new EmsPostControllerResult();
        if(!"2".equals(order.getStatus())){
            postControllerResult.setSuccess(Boolean.TRUE);
            return postControllerResult;
        }
        String province = order.getProvince();
        String city = order.getCity();
        String area = order.getArea();
        String address = order.getAddress();
        log.info("订单地址查询管控  orderNo:{},province:{},city:{},area:{},address:{}",orderNo,province,city,area,address);
        if(StringUtils.isAnyBlank(province,city,area,address)){
            postControllerResult.setSuccess(Boolean.TRUE);
            log.error("订单地址查询管控 地址为空 orderNo:{},province:{},city:{},area:{},address:{}",orderNo,province,city,area,
                    address);
            return postControllerResult;
        }
        OrderPostControllerAddressReq orderPostControllerAddressReq = new OrderPostControllerAddressReq();
        orderPostControllerAddressReq.setOrderNo(orderNo);
        orderPostControllerAddressReq.setReceiverProvinceName(province);
        orderPostControllerAddressReq.setReceiverCityName(city);
        orderPostControllerAddressReq.setReceiverCountyName(area);
        orderPostControllerAddressReq.setReceiverAddr(address);
        postControllerResult = emsService.doEmsPostController(orderPostControllerAddressReq);
        if(Objects.isNull(postControllerResult)){
            postControllerResult = new EmsPostControllerResult();
            postControllerResult.setSuccess(Boolean.TRUE);
            return postControllerResult;
        }
        if(!postControllerResult.getSuccess()&&"B99".equals(postControllerResult.getErrorCode())){
            postControllerResult.setErrorMsg("管控中");
            postControllerResult.setSuccess(Boolean.FALSE);
        }else{
            postControllerResult.setSuccess(Boolean.TRUE);
        }
        return postControllerResult;
    }

    private void importShippingBatch(byte[] inputStream, String batchId) {
        List<OrderImport> models = ExcelUtil.readData(new ByteArrayInputStream(inputStream), OrderImport.class);
        if (CollectionUtils.isEmpty(models)) {
            return;
        }
        Date date = new Date();
        List<OrderShippingTaskDetail> details = new ArrayList<>();
        for (OrderImport singleOrderImport : models) {
            if(StringUtils.isBlank(singleOrderImport.getFrom())){
                log.error("【发货地址不能为空】");
                throw new BusinessException("发货地址不能为空");
            }
            OrderShippingTaskDetail detail = new OrderShippingTaskDetail();
            BeanUtils.copyProperties(singleOrderImport, detail);
            detail.setOrderShippingTaskId(batchId);
            detail.setId(null);
            detail.setCreatedTime(date);
            details.add(detail);
        }
        mongoTemplate.insertAll(details);
        Query query1 = new Query().addCriteria(Criteria.where("id").is(batchId));
        Update update = new Update();
        update.set("totalNum", Long.valueOf(details.size() + ""));
        update.set("updatedTime", new Date());
        mongoTemplate.updateFirst(query1, update, OrderShippingTask.class);
        log.info(":>>> 导入发货任务批次:{} 数量:{}", batchId, details.size());
    }

    private Query checkIdAndQuery(String id) {
        if (StringUtils.isBlank(id)) {
            log.error(":发货批次ID 为空");
            throw new BusinessException("发货批次ID 为空");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        return query;

    }

    /**
     * 撤销发货记录
     *
     * @param task
     */
    private void redoShipping(OrderShippingTask task) {
        log.info(":>>> 开始撤销发货任务:{}", JSON.toJSONString(task));
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        Date date = new Date();
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                Update update = new Update();
                update.set("logisticsNo", "");
                update.set("logisticsCompany", "");
                update.set("status", "3");
                update.set("updatedTime", date);
                update.set("orderShippingTaskId", task.getId());
                FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
                findAndModifyOptions.upsert(Boolean.TRUE);
                findAndModifyOptions.returnNew(Boolean.TRUE);
                OOrderInfo subOrderModify = mongoTemplate.findAndModify(querySubOrder, update, findAndModifyOptions, OOrderInfo.class);
                log.info(":>>> 撤销:子订单:{}", detail.getSuborderNo());
                Query queryDetail = new Query().addCriteria(Criteria.where("id").is(detail.getId()));
                Update updateDetail = new Update();
                updateDetail.set("optLogisticsNo", oOrderInfo.getLogisticsNo());
                updateDetail.set("optLogisticsCompany", oOrderInfo.getLogisticsCompany());
                updateDetail.set("orderStatus", oOrderInfo.getStatus());
                updateDetail.set("updatedTime", new Date());
                mongoTemplate.updateFirst(queryDetail, updateDetail, OrderShippingTaskDetail.class);
                // 更新物流单号和订单状态
                this.updateOrderStatus(subOrderModify);
                this.updateLogisticsNo(oOrderInfo.getOrderNo());
            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("handledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);
        }
        task.setStatus("3");
        this.update(task);
    }

    /**
     * 取消撤销发货记录
     *
     * @param task
     */
    private void cancelRedoShipping(OrderShippingTask task) {
        log.info(":>>> 开始取消撤销发货任务:{}", JSON.toJSONString(task));
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        Date date = new Date();
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            if (StringUtils.isNotBlank(detail.getOptLogisticsNo())) {
                Update update = new Update();
                update.set("logisticsNo", detail.getOptLogisticsNo());
                update.set("logisticsCompany", detail.getOptLogisticsCompany());
                update.set("status", detail.getOrderStatus());
                update.set("updatedTime", date);
                update.set("orderShippingTaskId", task.getId());
                FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
                findAndModifyOptions.returnNew(Boolean.TRUE);
                findAndModifyOptions.upsert(Boolean.TRUE);
                OOrderInfo subOrderModify = mongoTemplate.findAndModify(querySubOrder, update, findAndModifyOptions, OOrderInfo.class);
                log.info(":>>> 取消撤销发货任务:子订单:{}", detail.getSuborderNo());
                this.updateOrderStatus(subOrderModify);
                this.updateLogisticsNo(oOrderInfo.getOrderNo());

            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("canceledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);

        }
        task.setStatus("1");
        this.update(task);
    }

    /**
     * 发货
     *
     * @param task
     */
    private void shipping(OrderShippingTask task) {
        log.info(":>>> 开始发货任务:{}", JSON.toJSONString(task));
        Date date = new Date();
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        List<DeliveryOrderSubMsgMQVO> batchShippingOrderList = new ArrayList<>(details.size());
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
//            if (!StringUtils.isBlank(oOrderInfo.getLogisticsNo())) {
//                log.error(":>>> 子订单物流单号不为空:{}", detail.getSuborderNo());
//                continue;
//            }
            Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(detail.getOrderNo()));
            OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
            if(Objects.isNull(orderInfo)){
                continue;
            }
            PayConfigPage payConfigPage = cachePayConfigService.findByActivityId(oOrderInfo.getActivityId());
            Update update = new Update();
            update.set("logisticsNo", detail.getLogisticsNo());
            update.set("logisticsCompany", detail.getLogisticsCompany());
            update.set("status", "4");
            update.set("updatedTime", date);
            update.set("shippingTime", date);
            update.set("from", detail.getFrom());
            update.set("orderShippingTaskId", task.getId());
            update.set("tips", "你的订单已发货，请注意查收，可点击下方按钮查看物流详情，若查看不到物流详情，是因为还在扫描出库中，请耐心等待3-5天后再次点击查看！");
            FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
            findAndModifyOptions.upsert(Boolean.TRUE);
            findAndModifyOptions.returnNew(Boolean.TRUE);
            OOrderInfo orderModify = mongoTemplate.findAndModify(querySubOrder, update, findAndModifyOptions, OOrderInfo.class);
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("handledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);
            this.updateOrderStatus(orderModify);
            //订单订阅
            String address = orderInfo.getProvince()+orderInfo.getCity()+orderInfo.getArea()+orderInfo.getAddress();
            KuaiDi100PollMapBodyDTO dto =
                    KuaiDi100PollMapBodyDTO.builder().
                            number(detail.getLogisticsNo()).
                            to(address).
                            orderNo(orderInfo.getOrderNo())
                            .subOrderNo(oOrderInfo.getOOrderNo())
                            .phone(orderInfo.getMobile())
                            .from(detail.getFrom())
                            .logisticsCompany(detail.getLogisticsCompany()).
                            build();
            kuaiDi100Service.pushRollMap(dto);
            //可能存在主从
            //this.updateLogisticsNo(detail.getOrderNo());
            cacheOrderService.remove(orderModify.getOrderNo(),orderModify.getAccountInfoId());
            if(!StringUtils.isAllBlank(detail.getOrderNo(), detail.getLogisticsNo(),detail.getLogisticsCompany())){
                DeliveryOrderSubMsgMQVO deliveryOrderSubMsgMQ = new DeliveryOrderSubMsgMQVO();
                deliveryOrderSubMsgMQ.setOrderNo(detail.getOrderNo());
                deliveryOrderSubMsgMQ.setLogisticsNo(detail.getLogisticsNo());
                deliveryOrderSubMsgMQ.setSubOrderNo(detail.getSuborderNo());
                deliveryOrderSubMsgMQ.setLogisticsCompany(detail.getLogisticsCompany());
                if(Objects.nonNull(payConfigPage.getMsgTemplateRemark())){
                    deliveryOrderSubMsgMQ.setRemark(payConfigPage.getMsgTemplateRemark());
                }
                batchShippingOrderList.add(deliveryOrderSubMsgMQ);
            }
        }
        task.setStatus("3");
        this.update(task);
        try {
            deliveryOrderSubMsgService.doDeliveryOrderSub(batchShippingOrderList);
        }catch (Exception e){
            log.error("订单发货订阅消息失败",e);
        }

    }

    /**
     * 补发
     *
     * @param task
     */
    private void reeShipping(OrderShippingTask task) {
        log.info(":>>> 开始补发货任务:{}", JSON.toJSONString(task));
        Date date = new Date();
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        List<DeliveryOrderSubMsgMQVO> batchShippingOrderList = new ArrayList<>(details.size());
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(detail.getOrderNo()));
            OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
            if(Objects.isNull(orderInfo)){
                continue;
            }
            PayConfigPage payConfigPage = cachePayConfigService.findByActivityId(oOrderInfo.getActivityId());
            log.info(":>>> 子订单号:{},原物流号:{},补发物流号:{}", oOrderInfo.getOOrderNo(), oOrderInfo.getLogisticsNo(), detail.getLogisticsNo());
            if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                // 避免物流单号重复
                if (!oOrderInfo.getLogisticsNo().equals(detail.getLogisticsNo())) {
                    Update update1 = new Update();
                    update1.set("status", "4");
                    update1.set("shippingTime", date);
                    update1.set("from", detail.getFrom());
                    update1.set("postSaleStatus", "1");
                    update1.set("postSaleLogisticsCompany", detail.getLogisticsCompany());
                    update1.set("postSaleLogisticsNo", detail.getLogisticsNo());
                    update1.set("orderShippingTaskId", task.getId());
                    update1.set("tips", "你的订单已发货，请注意查收，可点击下方按钮查看物流详情，若查看不到物流详情，是因为还在扫描出库中，请耐心等待3-5天后再次点击查看！");
                    UpdateResult updateResultSub = mongoTemplate.updateFirst(querySubOrder, update1, OOrderInfo.class);
                    log.info(":>>> 更新子订单:{},结果为:{}", detail.getSuborderNo(), updateResultSub.getModifiedCount());
                    //订单订阅
                    String address = orderInfo.getProvince()+orderInfo.getCity()+orderInfo.getArea()+orderInfo.getAddress();
                    KuaiDi100PollMapBodyDTO dto =
                            KuaiDi100PollMapBodyDTO.builder().
                                    number(detail.getLogisticsNo()).
                                    to(address).
                                    orderNo(orderInfo.getOrderNo())
                                    .subOrderNo(oOrderInfo.getOOrderNo())
                                    .phone(orderInfo.getMobile())
                                    .from(detail.getFrom()).
                                    logisticsCompany(detail.getLogisticsCompany()).
                                    build();
                    kuaiDi100Service.pushRollMap(dto);
                    this.updateLogisticsNo(detail.getOrderNo());
                    if(!StringUtils.isAllBlank(detail.getOrderNo(), detail.getLogisticsNo(),detail.getLogisticsCompany())){
                        DeliveryOrderSubMsgMQVO deliveryOrderSubMsgMQ = new DeliveryOrderSubMsgMQVO();
                        deliveryOrderSubMsgMQ.setOrderNo(detail.getOrderNo());
                        deliveryOrderSubMsgMQ.setSubOrderNo(detail.getSuborderNo());
                        deliveryOrderSubMsgMQ.setLogisticsCompany(detail.getLogisticsCompany());
                        deliveryOrderSubMsgMQ.setLogisticsNo(detail.getLogisticsNo());
                        if(Objects.nonNull(payConfigPage.getMsgTemplateRemark())){
                            deliveryOrderSubMsgMQ.setRemark(payConfigPage.getMsgTemplateRemark());
                        }
                        batchShippingOrderList.add(deliveryOrderSubMsgMQ);
                    }
                }
            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("handledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);
            cacheOrderService.remove(oOrderInfo.getOrderNo(),oOrderInfo.getAccountInfoId());
        }
        task.setStatus("3");
        this.update(task);
        try {
            deliveryOrderSubMsgService.doDeliveryOrderSub(batchShippingOrderList);
        }catch (Exception e){
            log.error("订单发货订阅消息失败",e);
        }
    }

    /**
     * 更新订单状态
     *
     * @param subOrderModify
     */
    private void updateOrderStatus(OOrderInfo subOrderModify) {
        if(Objects.isNull(subOrderModify)){
            return;
        }
        log.info(":>>> 开始更新订单状态:{}", subOrderModify.getOrderNo());
        Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(subOrderModify.getOrderNo()));
        OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            return;
        }
        Date now = new Date();
        //更新主订单发货发货状态
        //主订单状态
        String status = orderInfo.getStatus();
        //子订单状态
        String subStatus = subOrderModify.getStatus();
        if("4".equals(subOrderModify.getStatus())){
            //状态,0:待付款,1:已付款,2:制作中,3:待发货,4:待收货,5:已收货,6:订单完成,7:订单关闭,8:售后中,9:退款中,10:部分已发货
            if ("1".equals(status) || "2".equals(status) || "3".equals(status)|| "4".equals(status)) {
                Update update = new Update();
                update.set("status", "4");
                update.push("logisticsNos",subOrderModify.getLogisticsNo());
                update.set("updatedTime", now);
                update.set("tips", "你的订单已发货，请注意查收，可点击下方按钮查看物流详情，若查看不到物流详情，是因为还在扫描出库中，请耐心等待3-5天后再次点击查看！");
                mongoTemplate.updateFirst(queryOrder, update, OrderInfo.class);
            }
            return;
        }
        //取消\撤销发货
        if("3".equals(subStatus)){
            Update update = new Update();
            update.set("status", "3");
            update.set("updatedTime", now);
            mongoTemplate.updateFirst(queryOrder, update, OrderInfo.class);
        }
    }

    /**
     * 更新物流单号
     *
     * @param orderNo
     */
    private void updateLogisticsNo(String orderNo) {
        log.info(":>>> 开始更新物流单号:{}", orderNo);
        Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            log.info(":>>> 更新物流单号:{} 订单不存在", orderNo);
            return;
        }
        Query querySub = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        List<OOrderInfo> subs = mongoTemplate.find(querySub, OOrderInfo.class);
        if (CollectionUtils.isEmpty(subs)) {
            log.info(":>>> 更新物流单号:{} 子订单不存在", orderNo);
            return;
        }
        if (Objects.isNull(orderInfo.getLogisticsNos())) {
            orderInfo.setLogisticsNos(new ArrayList<>());
        }
        for (OOrderInfo oOrderInfo : subs) {
            if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                if (!orderInfo.getLogisticsNos().contains(oOrderInfo.getLogisticsNo())) {
                    orderInfo.getLogisticsNos().add(oOrderInfo.getLogisticsNo());
                }
            }
            if (StringUtils.isNotBlank(oOrderInfo.getPostSaleLogisticsNo())) {
                if (!orderInfo.getLogisticsNos().contains(oOrderInfo.getPostSaleLogisticsNo())) {
                    orderInfo.getLogisticsNos().add(oOrderInfo.getPostSaleLogisticsNo());
                }
            }
        }
        if (!CollectionUtils.isEmpty(orderInfo.getLogisticsNos())) {
            Update update = new Update();
            //update.set("logisticsNos", orderInfo.getLogisticsNos());
            update.set("updatedTime", new Date());
            mongoTemplate.updateFirst(queryOrder, update, OrderInfo.class);
        }
    }

    /**
     * 取消发货
     *
     * @param task
     */
    private void cancelShipping(OrderShippingTask task) {
        log.info(":>>> 取消发货任务:{}", JSON.toJSONString(task));
        Date date = new Date();
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo) || StringUtils.isBlank(oOrderInfo.getLogisticsNo())) {
                log.error(":>>> 子订单不存在:{},或物流单号为空", detail.getSuborderNo());
                continue;
            }
            Update update = new Update();
            update.set("logisticsNo", "");
            update.set("logisticsCompany", "");
            update.set("status", "3");
            update.set("updatedTime", date);
            update.set("orderShippingTaskId", task.getId());
            UpdateResult updateResult = mongoTemplate.updateFirst(querySubOrder, update, OOrderInfo.class);
            log.info(":>>> 发货:子订单:{} 结果为:{}", detail.getSuborderNo(), updateResult.getModifiedCount() > 0 ? true : false);
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("canceledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);
            oOrderInfo.setStatus("3");
            this.updateOrderStatusCancel(oOrderInfo);
            this.updateLogisticsNoCancel(detail.getOrderNo());
        }
        task.setStatus("1");
        this.update(task);
    }

    /**
     * 更新订单状态取消
     *
     * @param subOrderInfo
     */
    private void updateOrderStatusCancel(OOrderInfo subOrderInfo) {
            // 更新主订单
            Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(subOrderInfo.getOrderNo()));
            OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
            if (Objects.isNull(orderInfo)) {
                return;
            }
            //状态,0:待付款,1:已付款,2:制作中,3:待发货,4:待收货,5:已收货,6:订单完成,7:订单关闭,8:售后中,9:退款中,10:部分已发货
            if ("4".equals(orderInfo.getStatus())) {
                Update update = new Update();
                update.set("status", "3");
                update.set("updatedTime", new Date());
                mongoTemplate.updateFirst(queryOrder, update, OrderInfo.class);
            }


    }

    private void updateLogisticsNoCancel(String orderNo) {
        log.info(":>>> 开始更新物流单号:{}", orderNo);
        Query queryOrder = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        OrderInfo orderInfo = mongoTemplate.findOne(queryOrder, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            log.info(":>>> 更新物流单号:{} 订单不存在", orderNo);
            return;
        }
        Query querySub = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        List<OOrderInfo> subs = mongoTemplate.find(querySub, OOrderInfo.class);
        if (CollectionUtils.isEmpty(subs)) {
            log.info(":>>> 更新物流单号:{} 子订单不存在", orderNo);
            return;
        }
        if (Objects.isNull(orderInfo.getLogisticsNos())) {
            orderInfo.setLogisticsNos(new ArrayList<>());
        }
        if (!CollectionUtils.isEmpty(orderInfo.getLogisticsNos())) {
            orderInfo.setLogisticsNos(new ArrayList<>());
        }
        for (OOrderInfo oOrderInfo : subs) {
            if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                if (!orderInfo.getLogisticsNos().contains(oOrderInfo.getLogisticsNo())) {
                    orderInfo.getLogisticsNos().add(oOrderInfo.getLogisticsNo());
                }
            }
            if (StringUtils.isNotBlank(oOrderInfo.getPostSaleLogisticsNo())) {
                if (!orderInfo.getLogisticsNos().contains(oOrderInfo.getPostSaleLogisticsNo())) {
                    orderInfo.getLogisticsNos().add(oOrderInfo.getPostSaleLogisticsNo());
                }
            }
        }
        if (!CollectionUtils.isEmpty(orderInfo.getLogisticsNos())) {
            Update update = new Update();
            update.set("logisticsNos", orderInfo.getLogisticsNos());
            update.set("updatedTime", new Date());
            mongoTemplate.updateFirst(queryOrder, update, OrderInfo.class);
        }
    }

    private void cancelReeShipping(OrderShippingTask task) {
        log.info(":>>> 开始撤销补发货任务:{}", JSON.toJSONString(task));
        Date date = new Date();
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            log.info(":>>> 子订单号:{},原物流号:{},补发物流号:{}", oOrderInfo.getOOrderNo(), oOrderInfo.getLogisticsNo(), detail.getLogisticsNo());
            if (StringUtils.isNotBlank(oOrderInfo.getPostSaleLogisticsNo())) {
                // 避免物流单号重复
                Update update1 = new Update();
                update1.set("status", "3");
                update1.set("postSaleStatus", "0");
                update1.set("postSaleLogisticsCompany", "");
                update1.set("postSaleLogisticsNo", "");
                update1.set("orderShippingTaskId", task.getId());
                UpdateResult updateResultSub = mongoTemplate.updateFirst(querySubOrder, update1, OOrderInfo.class);
                log.info(":>>> 更新子订单:{},结果为:{}", detail.getSuborderNo(), updateResultSub.getModifiedCount());
                this.updateLogisticsNo(detail.getOrderNo());

            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("canceledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);
        }
        task.setStatus("1");
        this.update(task);
    }

    /**
     * 撤销补发货记录
     *
     * @param task
     */
    private void redoReeShipping(OrderShippingTask task) {
        log.info(":>>> 开始撤销补发货任务:{}", JSON.toJSONString(task));
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        Date date = new Date();
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            if (StringUtils.isNotBlank(oOrderInfo.getPostSaleLogisticsNo())) {
                Update update = new Update();
                update.set("postSaleLogisticsNo", "");
                update.set("postSaleLogisticsCompany", "");
                update.set("postSaleStatus", "0");
                update.set("updatedTime", date);
                update.set("orderShippingTaskId", task.getId());
                FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
                findAndModifyOptions.returnNew(Boolean.TRUE);
                findAndModifyOptions.upsert(Boolean.TRUE);
                OOrderInfo subOrderModify = mongoTemplate.findAndModify(querySubOrder, update, findAndModifyOptions, OOrderInfo.class);
                log.info(":>>> 撤销:子订单:{} 结果为:{}", detail.getSuborderNo());
                Query queryDetail = new Query().addCriteria(Criteria.where("id").is(detail.getId()));
                Update updateDetail = new Update();
                updateDetail.set("optPostSaleLogisticsNo", oOrderInfo.getPostSaleLogisticsNo());
                updateDetail.set("optPostSaleLogisticsCompany", oOrderInfo.getPostSaleLogisticsCompany());
                updateDetail.set("optPostSaleStatus", oOrderInfo.getPostSaleStatus());
                updateDetail.set("updatedTime", new Date());
                mongoTemplate.updateFirst(queryDetail, updateDetail, OrderShippingTaskDetail.class);
                this.updateOrderStatus(subOrderModify);
                this.updateLogisticsNo(oOrderInfo.getOrderNo());
            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("handledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);


        }
        task.setStatus("3");
        this.update(task);
    }

    /**
     * 回滚撤销补发货记录
     *
     * @param task
     */
    private void cancelRedoReeShipping(OrderShippingTask task) {
        log.info(":>>> 开始回滚撤销补发货任务:{}", JSON.toJSONString(task));
        Query query1 = new Query().addCriteria(Criteria.where("orderShippingTaskId").is(task.getId()));
        List<OrderShippingTaskDetail> details = mongoTemplate.find(query1, OrderShippingTaskDetail.class);
        if (CollectionUtils.isEmpty(details)) {
            log.error(":>>> 任务明细:{} 不存在", task.getId());
            return;
        }
        Date date = new Date();
        for (OrderShippingTaskDetail detail : details) {
            Query querySubOrder = new Query().addCriteria(Criteria.where("oOrderNo").is(detail.getSuborderNo()));
            OOrderInfo oOrderInfo = mongoTemplate.findOne(querySubOrder, OOrderInfo.class);
            if (Objects.isNull(oOrderInfo)) {
                log.error(":>>> 子订单不存在:{}", detail.getSuborderNo());
                continue;
            }
            log.info(":>>> 补发的物流单号opt:{}", detail.getOptPostSaleLogisticsNo());
            if (StringUtils.isNotBlank(detail.getOptPostSaleLogisticsNo())) {
                Update update = new Update();
                update.set("postSaleLogisticsNo", detail.getOptPostSaleLogisticsNo());
                update.set("postSaleLogisticsCompany", detail.getOptPostSaleLogisticsCompany());
                update.set("postSaleStatus", detail.getOptPostSaleStatus());
                update.set("updatedTime", date);
                update.set("orderShippingTaskId", task.getId());
                FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
                findAndModifyOptions.upsert(Boolean.TRUE);
                findAndModifyOptions.returnNew(Boolean.TRUE);
                OOrderInfo subOrderModify = mongoTemplate.findAndModify(querySubOrder, update, OOrderInfo.class);
                log.info(":>>> 回滚撤销:子订单:{} 结果为:{}", detail.getSuborderNo());
                this.updateOrderStatus(subOrderModify);
                this.updateLogisticsNo(oOrderInfo.getOrderNo());
            }
            Query queryTask = new Query().addCriteria(Criteria.where("id").is(task.getId()));
            Update updateTask = new Update();
            updateTask.inc("canceledNum", 1);
            updateTask.set("updatedTime", date);
            mongoTemplate.updateFirst(queryTask, updateTask, OrderShippingTask.class);

        }
        task.setStatus("1");
        this.update(task);
    }

}
